﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web.UI;

namespace Niknak.Services.TaskScheduler.UI.Web
{
    /// <summary>
    /// See http://www.codegolem.com/post/UserControl-as-a-DLL-made-easy.aspx
    /// </summary>
    public abstract class EmbeddedUserControl : UserControl
    {
        private string _markupName;

        public EmbeddedUserControl(string markupName)
        {
            _markupName = markupName;
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            // loads markup from embedded resource
            string content = String.Empty;
            Stream stream = Assembly.GetAssembly(GetType()).GetManifestResourceStream(GetType(), _markupName);
            using (StreamReader reader = new StreamReader(stream))
            {
                content = reader.ReadToEnd();
            }
            Control userControl = Page.ParseControl(content);
            Controls.Add(userControl);

            // binds child controls and events
            BindControls(userControl);
        }

        private void BindControls(Control control)
        {
            Type type = GetType();
            string fieldTypeString;

            foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
            {
                fieldTypeString = fieldInfo.FieldType.ToString().ToLowerInvariant();
                if (fieldTypeString.StartsWith("system.web.ui.webcontrols.") || fieldTypeString.StartsWith("system.web.ui.htmlcontrols."))
                    ProcessField(control, fieldInfo, fieldInfo.Name);
                else
                    foreach (MarkupControlAttribute attribute in fieldInfo.GetCustomAttributes(typeof(MarkupControlAttribute), true))
                        ProcessField(control, fieldInfo, string.IsNullOrEmpty(attribute.ID) ? fieldInfo.Name : attribute.ID);
            }
        }

        private void ProcessField(Control control, FieldInfo field, string fieldId)
        {
            Control childControl = control.FindControl(fieldId);
            field.SetValue(this, childControl);

            foreach (MarkupControlEventAttribute eventAttribute in field.GetCustomAttributes(typeof(MarkupControlEventAttribute), true))
            {
                string eventName = eventAttribute.EventName;
                string eventHandler = eventAttribute.EventHandler;
                EventInfo eventInfo = childControl.GetType().GetEvent(eventName);

                Delegate eventDelegate = Delegate.CreateDelegate(eventInfo.EventHandlerType, this, GetType().GetMethod(eventHandler,
                    BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic));
                eventInfo.AddEventHandler(childControl, eventDelegate);
            }
        }
    }
}
